%skeleton "lalr1.cc" // -*- C++ -*-
%require "3.6"
%defines

%define api.token.raw

%define api.token.constructor
%define api.value.type variant
//%define api.value.type {string}
%define parse.assert

%code requires {
//#include <string>
//#include <iostream>
//#include "std.h"
//#include "AstNode.h"
class AstNode;
    using namespace std;
    class driver;
}

// The parsing context.
%param { driver& drv }

%locations

%define parse.trace
%define parse.error detailed
%define parse.lac full

%code {
#include "driver.h"
}

%define api.token.prefix {TOK_}

// 终结符
%token IF "if"
%token ELSE "else"
%token WHILE "while"
%token BREAK "break"
%token CONTINUE "continue"
%token RETURN "return"
%token CASE "case"
%token DEFAULT "default"
%token SWITCH "switch"
%token DO "do"
%token FOR "for"
%token GOTO "goto"

%token INT "int"
%token VOID "void"
%token CONST "const"
%token AUTO "auto"
%token REGISTER "register"
%token STATIC "static"
%token EXTERN "extern"
%token TYPEDEF "typedef"
%token CHAR "char"
%token SHORT "short"
%token LONG "long"
%token FLOAT "float"
%token DOUBLE "double"
%token SIGNED "signed"
%token UNSIGNED "unsigned"
%token VOLATILE "volatile"
%token STRUCT "struct"
%token UNION "union"
%token ENUM "enum"

%token ASSIGN "="
%token MINUS "-"
%token PLUS "+"
%token STAR "*"
%token SLASH "/"
%token LPAREN "("
%token RPAREN ")"
%token LBRACE "{"
%token RBRACE "}"
%token LBRACKET "["
%token RBRACKET "]"
%token SEMICOLON ";"
%token COLON ":"
%token COMMA ","
%token ELLIPSIS "..."
%token MUL_ASSIGN "*="
%token DIV_ASSIGN "/="
%token MOD_ASSIGN "%="
%token PLUS_ASSIGN "+="
%token MINUS_ASSIGN "-="
%token LEFT_SHIFT_ASSIGN "<<="
%token RIGHT_SHIFT_ASSIGN ">>="
%token AND_ASSIGN "&="
%token BITWISE_XOR_ASSIGN "^="
%token BITWISE_OR_ASSIGN "|="
%token BITWISE_QUESTION "?"
%token OR "||"
%token AND "&&"
%token BITWISE_OR "|"
%token BITWISE_XOR "^"
%token BITWISE_AND "&"
%token EQ "=="
%token NOT_EQ "!="
%token LT "<"
%token GT ">"
%token LT_EQ "<="
%token GT_EQ ">="
%token LEFT_SHIFT "<<"
%token RIGHT_SHIFT ">>"
%token PERCENT "%"
%token INC "++"
%token DEC "--"
%token SIZEOF "sizeof"
%token TILDE "~"
%token EXCLAMATION "!"
%token DOT "."
%token ARROW "->"

%token STRING "string"
%token <std::string> INTEGER_CONSTANT "integer_constant"
%token CHARACTER_CONSTANT "character_constant"
%token FLOATING_CONSTANT "floating_constant"
%token ENUMERATION_CONSTANT "enumeration_constant"
%token <std::string> IDENTIFIER "identifier"



// 非终结符
%nterm <AstNode*> translation_unit
%nterm <AstNode*> external_declaration
%nterm <AstNode*> function_definition
%nterm <AstNode*> declaration
%nterm <AstNode*> declaration_list
%nterm <AstNode*> declaration_specifiers
%nterm <AstNode*> storage_class_specifier
%nterm <AstNode*> type_specifier
%nterm <AstNode*> type_qualifier
%nterm <AstNode*> struct_or_union_specifier
%nterm <AstNode*> struct_or_union
%nterm <AstNode*> struct_declaration_list
%nterm <AstNode*> init_declarator_list
%nterm <AstNode*> init_declarator
%nterm <AstNode*> struct_declaration
%nterm <AstNode*> specifier_qualifier_list
%nterm <AstNode*> struct_declarator_list
%nterm <AstNode*> struct_declarator
%nterm <AstNode*> enum_specifier
%nterm <AstNode*> enumerator_list
%nterm <AstNode*> enumerator
%nterm <AstNode*> declarator
%nterm <AstNode*> direct_declarator
%nterm <AstNode*> pointer
%nterm <AstNode*> type_qualifier_list
%nterm <AstNode*> parameter_type_list
%nterm <AstNode*> parameter_list
%nterm <AstNode*> parameter_declaration
%nterm <AstNode*> identifier_list
%nterm <AstNode*> initializer
%nterm <AstNode*> initializer_list
%nterm <AstNode*> type_name
%nterm <AstNode*> abstract_declarator
%nterm <AstNode*> direct_abstract_declarator
%nterm <AstNode*> statement
%nterm <AstNode*> labeled_statement
%nterm <AstNode*> expression_statement
%nterm <AstNode*> compound_statement
%nterm <AstNode*> statement_list
%nterm <AstNode*> selection_statement
%nterm <AstNode*> iteration_statement
%nterm <AstNode*> jump_statement
%nterm <AstNode*> expression
%nterm <AstNode*> assignment_expression
%nterm <AstNode*> assignment_operator
%nterm <AstNode*> conditional_expression
%nterm <AstNode*> constant_expression
%nterm <AstNode*> logical_OR_expression
%nterm <AstNode*> logical_AND_expression
%nterm <AstNode*> inclusive_OR_expression
%nterm <AstNode*> exclusive_OR_expression
%nterm <AstNode*> AND_expression
%nterm <AstNode*> equality_expression
%nterm <AstNode*> relational_expression
%nterm <AstNode*> shift_expression
%nterm <AstNode*> additive_expression
%nterm <AstNode*> multiplicative_expression
%nterm <AstNode*> cast_expression
%nterm <AstNode*> unary_expression
%nterm <AstNode*> unary_operator
%nterm <AstNode*> postfix_expression
%nterm <AstNode*> primary_expression
%nterm <AstNode*> argument_expression_list
%nterm <AstNode*> constant

%printer { yyo << $$; } <*>;

%%
/*
%start unit;
unit: assignments exp  { drv.result = $2; };

assignments:
  %empty                 {}
| assignments assignment {};

assignment:
  "identifier" ":=" exp { drv.variables[$1] = $3; };

%left "+" "-";
%left "*" "/";
exp:
  "number"
| "identifier"  { $$ = drv.variables[$1]; }
| exp "+" exp   { $$ = $1 + $3; }
| exp "-" exp   { $$ = $1 - $3; }
| exp "*" exp   { $$ = $1 * $3; }
| exp "/" exp   { $$ = $1 / $3; }
| "(" exp ")"   { $$ = $2; }
*/



%start translation_unit;

translation_unit:
  external_declaration
| translation_unit external_declaration
;

external_declaration: // 这个external是指这些声明在函数之外
  function_definition
| declaration
;

function_definition:
  declarator compound_statement {std::cout << "haha1\n"; }
| declarator declaration_list compound_statement {std::cout << "haha2\n"; }
| declaration_specifiers declarator compound_statement { std::cout << "(function " + $2 + " " + $1 + " " + $3 +")"; }
| declaration_specifiers declarator declaration_list compound_statement {std::cout << "haha4\n"; }
;

declaration:
  declaration_specifiers ";"
| declaration_specifiers init_declarator_list ";"
;

declaration_list:
  declaration
| declaration_list declaration
;

declaration_specifiers:
  storage_class_specifier
| storage_class_specifier declaration_specifiers
| type_specifier
| type_specifier declaration_specifiers
| type_qualifier
| type_qualifier declaration_specifiers
;

storage_class_specifier:
  "auto" { $$ = "auto"; }
| "register" { $$ = "register"; }
| "static" { $$ = "static"; }
| "extern" { $$ = "extern"; }
| "typedef" { $$ = "typedef"; }
;

type_specifier:
  "void" { $$ = "void"; }
| "char" { $$ = "char"; }
| "short" { $$ = "short"; }
| "int" { $$ = "int"; }
| "long" { $$ = "long"; }
| "float" { $$ = "float"; }
| "double" { $$ = "double"; }
| "signed" { $$ = "signed"; }
| "unsigned" { $$ = "unsigned"; }
| struct_or_union_specifier
| enum_specifier
;
//| typedef_name

type_qualifier:
  "const" { $$ = "const"; }
| "volatile" { $$ = "volatile"; }
;

struct_or_union_specifier:
  struct_or_union "{" struct_declaration_list "}"
| struct_or_union "identifier" "{" struct_declaration_list "}"
| struct_or_union "identifier"
;

struct_or_union:
  "struct" { $$ = "struct"; }
| "union" { $$ = "union"; }
;

struct_declaration_list:
  struct_declaration
| struct_declaration_list struct_declaration
;

init_declarator_list:
  init_declarator
| init_declarator_list "," init_declarator
;

init_declarator:
  declarator
| declarator "=" initializer
;

struct_declaration:
  specifier_qualifier_list struct_declarator_list ";"
;

specifier_qualifier_list:
  type_specifier
| type_specifier specifier_qualifier_list
| type_qualifier
| type_qualifier specifier_qualifier_list
;

struct_declarator_list:
  struct_declarator
| struct_declarator_list "," struct_declarator
;

struct_declarator:
  declarator
| ":" constant_expression {}
| declarator ":" constant_expression
;

enum_specifier:
  "enum" "{" enumerator_list "}" {}
| "enum" "identifier" "{" enumerator_list "}" {}
| "enum" "identifier" {}
;

enumerator_list:
  enumerator
| enumerator_list "," enumerator
;

enumerator:
  "identifier" { $$ = new AstNode; }
| "identifier" "=" constant_expression { $$ = new AstNode; }
;

declarator:
  direct_declarator
| pointer direct_declarator
;

direct_declarator:
  "identifier" { $$ = new AstNode; }
| "(" declarator ")" {}
| direct_declarator "[" "]"
| direct_declarator "[" constant_expression "]"
| direct_declarator "(" parameter_type_list ")" { std::cout << "oops\n"; }
| direct_declarator "(" ")"
| direct_declarator "(" identifier_list ")"
;

pointer:
  "*" {}
| "*" type_qualifier_list {}
| "*" pointer {}
| "*" type_qualifier_list pointer {}
;

type_qualifier_list:
  type_qualifier
| type_qualifier_list type_qualifier
;

parameter_type_list:
  parameter_list
| parameter_list "," "..."
;

parameter_list:
  parameter_declaration
| parameter_list "," parameter_declaration
;

parameter_declaration:
  declaration_specifiers declarator
| declaration_specifiers
| declaration_specifiers abstract_declarator
;

identifier_list:
  "identifier" { $$ = new AstNode; }
| identifier_list "," "identifier"
;

initializer:
  assignment_expression
| "{" initializer_list "}" {}
| "{" initializer_list "," "}" {}
;

initializer_list:
  initializer
| initializer_list "," initializer
;

type_name:
  specifier_qualifier_list
| specifier_qualifier_list abstract_declarator
;

abstract_declarator:
  pointer
| direct_abstract_declarator
| pointer direct_abstract_declarator
;

direct_abstract_declarator:
  "(" abstract_declarator ")" {}
| "[" "]" {}
| "[" constant_expression "]" {}
| direct_abstract_declarator "[" "]"
| direct_abstract_declarator "[" constant_expression "]"
| "(" ")" {}
| "(" parameter_type_list ")" {}
| direct_abstract_declarator "(" ")" {}
| direct_abstract_declarator "(" parameter_type_list ")"
;

/*
typedef_name:
  identifier
*/

statement:
  labeled_statement
| expression_statement
| compound_statement
| selection_statement
| iteration_statement
| jump_statement
;

labeled_statement:
  "identifier" ":" statement {}
| "case" constant_expression ":" statement {}
| "default" ":" statement {}
;

expression_statement:
  ";" {}
| expression ";"
;

compound_statement:
  "{" "}" {}
| "{" statement_list "}" { $$ = "(block " + $2 + ")"; }
| "{" declaration_list "}" {}
| "{" declaration_list statement_list "}" {}
;

statement_list:
  statement
| statement_list statement
;

selection_statement:
  "if" "(" expression ")" statement {}
| "if" "(" expression ")" statement "else" statement {}
| "switch" "(" expression ")" statement {}
;

iteration_statement:
  "while" "(" expression ")" statement {}
| "do" statement "while" "(" expression ")" ";" {}
| "for" "(" ";" ";" ")" statement {}
| "for" "(" ";" ";" expression ")" statement {}
| "for" "(" ";" expression ";" ")" statement {}
| "for" "(" ";" expression ";" expression ")" statement {}
| "for" "(" expression ";" ";" ")" statement {}
| "for" "(" expression ";" ";" expression ")" statement {}
| "for" "(" expression ";" expression ";" ")" statement {}
| "for" "(" expression ";" expression ";" expression ")" statement {}
;

jump_statement:
  "goto" "identifier" ";" {}
| "continue" ";" {}
| "break" ";" {}
| "return" ";" {}
| "return" expression ";" { $$ = "(return " + $2 + ")"; }
;

expression:
  assignment_expression
| expression "," assignment_expression
;

assignment_expression:
  conditional_expression
| unary_expression assignment_operator assignment_expression
;

assignment_operator:
  "=" {}
| "*=" {}
| "/=" {}
| "%=" {}
| "+=" {}
| "-=" {}
| "<<=" {}
| ">>=" {}
| "&=" {}
| "^=" {}
| "|=" {}
;

conditional_expression:
  logical_OR_expression
| logical_OR_expression "?" expression ":" conditional_expression
;

constant_expression:
  conditional_expression
;

logical_OR_expression:
  logical_AND_expression
| logical_OR_expression "||" logical_AND_expression
;

logical_AND_expression:
  inclusive_OR_expression
| logical_AND_expression "&&" inclusive_OR_expression
;

inclusive_OR_expression:
  exclusive_OR_expression
| inclusive_OR_expression "|" exclusive_OR_expression
;

exclusive_OR_expression:
  AND_expression
| exclusive_OR_expression "^" AND_expression
;

AND_expression:
  equality_expression
| AND_expression "&" equality_expression
;

equality_expression:
  relational_expression
| equality_expression "==" relational_expression
| equality_expression "!=" relational_expression
;

relational_expression:
  shift_expression
| relational_expression "<" shift_expression
| relational_expression ">" shift_expression
| relational_expression "<=" shift_expression
| relational_expression ">=" shift_expression
;

shift_expression:
  additive_expression
| shift_expression "<<" additive_expression
| shift_expression ">>" additive_expression
;

additive_expression:
  multiplicative_expression
| additive_expression "+" multiplicative_expression { $$ += "(+ " + $1 + " " + $3 + ")"; }
| additive_expression "-" multiplicative_expression
;

multiplicative_expression:
  cast_expression
| multiplicative_expression "*" cast_expression
| multiplicative_expression "/" cast_expression
| multiplicative_expression "%" cast_expression
;

cast_expression:
  unary_expression
| "(" type_name ")" cast_expression {}
;

unary_expression:
  postfix_expression
| "++" unary_expression {}
| "--" unary_expression {}
| unary_operator cast_expression
| "sizeof" unary_expression {}
| "sizeof" "(" type_name ")" {}
;

unary_operator:
  "&" {}
| "*" {}
| "+" {}
| "-" {}
| "~" {}
| "!" {}
;

postfix_expression:
  primary_expression
| postfix_expression "[" expression "]"
| postfix_expression "(" ")"
| postfix_expression "(" argument_expression_list ")"
| postfix_expression "." "identifier"
| postfix_expression "->" "identifier"
| postfix_expression "++"
| postfix_expression "--"
;

primary_expression:
  "identifier" { $$ = new AstNode; }
| constant
| "string" {}
| "(" expression ")" {}
;

argument_expression_list:
  assignment_expression
| argument_expression_list "," assignment_expression
;

constant:
  "integer_constant" { $$ = new Constant1(2); }
| "character_constant" {}
| "floating_constant" {}
| "enumeration_constant" {}
;


%%

void
yy::parser::error (const location_type& l, const std::string& m)
{
  std::cerr << l << ": " << m << '\n';
}
